import {installRenderHelper} from "./renderHelper";
import {complie} from "../../complier";
import {isDef} from "../../shared/util";
import {_createElement} from "./create/create-element";


/**
 *
 * @param {Function} Reactive
 */
export function renderMixin (Reactive) {

    installRenderHelper(Reactive);

}

/**
 * 解析 slots 插槽节点渲染函数数组，
 * 将其转换为 slotName => { name: xxx, scopeAlias: xxx, renderCode: xxx } 键值对
 * 并存储在 Object 类型上
 * @param slotArray 插槽节点渲染函数数组
 * @return {{default: *[]}}
 */
function resolveSlots (slotArray) {
    const slots = {
        default: []
    };
    for (let i=0; i<slotArray.length; i++) {
        const slotItem = slotArray[i];
        // 编译 插槽节点 渲染函数代码
        slotItem.render = new Function(slotItem.renderCode);
        // 将对应的插槽节点对象放入 slots 中
        const name = slotItem.name;
        name === 'default'
            ? slots[name].push(slotItem)
            : slots[name] = slotItem;
    }
    return slots;
}

/**
 * 目前这里在此处生成 ViewModel 所需要的模板以及渲染函数代码
 * @param {Reactive} vm Reactive实例
 */
export function initRender (vm) {
    // 获取挂载节点
    if (vm.$options.el) {
        const node = document.querySelector(vm.$options.el);
        if (isDef(node)) {
            vm.elem = node;
        }
        else {
            throw new Error("请为 Reactive 选择一个挂载的DOM节点");
        }
    }

    // 设置该实例是否是组件实例
    if (vm.$options.isComponent) {
        vm.isComponent = vm.$options.isComponent;
    }
    // 解析插槽节点数组, 渲染为 key=> value 键值对的形式
    if (vm.$options.slots) {
        vm.slots = resolveSlots(vm.$options.slots);
    }
    // 设置该组件实例的父亲组件实例
    if (vm.$options.parentComponent) {
        vm.parentComponent = vm.$options.parentComponent;
    }

    // 设置组件父节点
    isDef(vm.$options.parent)
        ? vm.parent = vm.$options.parent
        : vm.parent = isDef(vm.elem)
            ? vm.elem.parentElement
            : null;
    if (isDef(vm.elem) && vm.elem.tag === "document") {
        throw new Error("挂载节点无父节点, 请不要把 elem 指向 document.");
    }

    // 设置占位节点信息
    isDef(vm.$options.placeholder)
        ? vm.placeholder = vm.$options.placeholder
        : vm.placeholder = null;

    // 获取模板信息
    if (isDef(vm.$options.template)) {
        vm.template = vm.$options.template;
    }
    // 初始化 createElement 函数
    vm._c = (tag, data, children, options) => _createElement(vm, tag, data, children, options);
    // 获取渲染代码
    vm.renderCode = complie(vm.template, vm);
    // 获得渲染函数的实例
    const renderCode = vm.renderCode.renderFn;
    vm.render = new Function(renderCode);
}

